#ifndef fit_pro_hh
#define fit_pro_hh 1

#include <iostream>
#include <TFile.h>
#include <TTree.h>
#include <vector>
#include <TH1I.h>
#include <TF1.h>
#include <TCanvas.h>
#include <TGraphErrors.h>
#include <TPaveStats.h>
#include <iomanip>
#include "TROOT.h"
#include <TH2D.h>
#include <TLegend.h>
#include <TStyle.h>
#include <TLatex.h>

#include <string>
#include <vector>
#include <filesystem>
#include <algorithm>
#include <numeric>

#include <eigen3/Eigen/Dense>
#include <Eigen/Dense>
#include <boost/math/quadrature/trapezoidal.hpp>
#include <boost/math/constants/constants.hpp>
#include <cmath>
#include <fstream>
#include "constant.hh"
#include "position_data.hh"
#include "track_data.hh"
#include "MyTracker.hh"
#include <random>

#include "json.hh"

using namespace std;
using json = nlohmann::basic_json<nlohmann::ordered_map>;
using namespace Eigen;
using namespace boost::math::quadrature;

class fit_pro
{
public:
    fit_pro(string input_file_name, string align_filename, string rotate_filename, string range_filename, float fit_rmse, bool is_have_target_det, int target_det_idx, int use_set_layer_used, double eff_sigma, double ADC_LSB, string save_path, bool is_write_waitalign_data, bool is_write_event_json, bool is_fit_control_angle, double angle_deg, string save_path_event, bool is_region_eff, int region_number);
    ~fit_pro();

    bool is_file_get = false;

    int det_layer_used;
    int target_det_idx = 10;
    int use_set_layer_used;
    bool is_have_target_det;
    float fit_rmse;
    double eff_sigma;
    double ADC_LSB;
    string save_path;
    string save_path_event;
    bool is_write_waitalign_data;
    bool is_write_event_json;
    bool is_fit_control_angle;
    double angle_deg;

    bool is_align = false;
    bool is_rotate = false;
    bool is_region_eff = false;
    int region_number = 4;

private:
    //
    bool user_layer[cMAX_DET_LAYER] = {false};

    vector<float> x_alignment;
    vector<float> y_alignment;
    vector<float> z_alignment;

    vector<Matrix<float, 3, 3>> rotate_matrix;

    // 读取root文件
    int total_entried_num = 0;
    int valid_det_num = 0;
    TFile *hit_data_file;
    TTree *hit_data_tree;
    int trigger_id;
    int total_layer_num;
    position_data detector_data[cMAX_DET_LAYER];
    TBranch *b_triggera_id;
    TBranch *b_total_layer_num;
    TBranch *b_detector_data[cMAX_DET_LAYER];

    vector<float> alignment;
    vector<float> rotate_data;

    vector<int> dec_idx;

    vector<float> fit_range;
    vector<float> dec_construct;
    float fit_location = 0;

    // alignment
    double tx;
    double ty;
    double tz;

    Matrix<float, 3, 3> rotate_matrix_target;

    // 效率计算
    int fit_vld_numx = 0;
    int fit_vld_numy = 0;
    int target_vld_numx = 0;
    int target_vld_numy = 0;

    vector<vector<int>> ref_region_effx, ref_region_effy, ref_region_par;
    vector<vector<int>> target_region_effx, target_region_effy, target_region_par;
    vector<vector<float>> region_par_amp;

    // fit result
    vector<vector<float>> fec_fit_datax;
    vector<vector<float>> fec_fit_datay;

    // spatial calulate
    vector<float> rmsx, ampx, clusterx, chnx, x_all;
    vector<float> rmsy, ampy, clustery, chny, y_all;
    vector<int> targe_vld_idx, targe_vld_idy;
    vector<float> ampall;

    // out
    ofstream outall;

    // read detector index
    void set_layer_used();
    // read alignment
    bool read_dec_file(string filename, vector<float> &dec);
    // read root file
    int read_root_file(string data_infilename);
    // read alignment
    void read_alignment();
    // read rotate
    void read_rotate();

    bool is_identity_matrix(const Eigen::Matrix<float, 3, 3> &matrix);

    // main process
    bool run();

    // 筛选出每次缪子事件中可能存在的径迹组合
    bool fit_data_select(float *event_det_chn, float *event_det_cluster, int *event_det_idx, int event_det_size, int &assembly_num, float *&fit_data, float *&fit_cluster);

    // 径迹组合过滤
    bool data_filter(int num, float *wait_fliter_data, float *wait_fliter_cluster, int &fliter_size, float *&fliter_over_data, float *&fliter_over_cluster);

    void data_rotate(int numx, int numy, float *wait_rotatex, float *wait_rotatey, float *wait_clusterx, float *wait_clustery, float *&det_rotatex, float *&det_rotatey, float *&det_rotatez, float *&det_clusterx, float *&det_clustery, int &output_size);

    // 挑选出每次缪子事件中最优的径迹，然后反推到待测探测器上
    void det_data_fit(int num, float *fec_data_combine, float *fec_data_z, float *fec_data_combine_cluster, bool is_x_direction, float &vld_fit_hit, float &vld_fit_slope, float &vld_fit_intercept);

    void det_data_fitv2(int num, float *fec_data_combine_x, float *fec_data_combine_y, float *fec_data_z, float *fec_data_combine_cluster_x, float *fec_data_combine_cluster_y, float &vld_fit_hit_x, float &vld_fit_hit_y, float &vld_fit_slope_x, float &vld_fit_slope_y, float &vld_fit_intercept_x, float &vld_fit_intercept_y);

    // 计算目标层每个事例位置分辨等信息
    void calculateSpatial(float *target_det_rz, float *target_det_chn, float *target_det_amp, float *target_det_clu, int target_det_size, float fit_hit, float fit_slope, float fit_intercept, float align_data, float &amp, float &chn, float &clu, float &x_err, float &y_err, bool is_x_direction);
    void target_rotate(int numx, int numy, float *wait_rotatex, float *wait_rotatey, float *wait_clusterx, float *wait_clustery, float *wait_ampx, float *wait_ampy, float *&det_rotatex, float *&det_rotatey, float *&det_rotatez, float *&det_clusterx, float *&det_clustery, float *&det_ampx, float *&det_ampy, int &output_size);

    // 画图
    void draw_spatial(vector<float> rms, bool xory);

    void draw_energy(vector<float> energy, bool xory);

    void draw_all_energy(vector<float> energy);

    void draw_cluster(vector<float> cluster, bool xory);

    void draw_hit_range_xy();

    void draw_hit_strip(vector<float> ss, bool xory);

    void draw_region_efficiency();
    void draw_region_amp();

    // 新建输出文件
    void out_result();

    // 输出到root文件
    TFile *adas_track_file;
    TTree *adas_track_tree;
    int event_id;
    track_data detector_vld_data[cMAX_DET_LAYER];
    float x_slope;
    float x_Intercept;
    float y_slope;
    float y_Intercept;

    // 输出到root文件
    TFile *adas_target_file;
    TTree *adas_target_tree;
    float x_rmse, y_rmse;
    float x_amp, y_amp;
    float x_pos, y_pos, z_pos;
    float x_pos_err, y_pos_err;
    int x_strip_number, y_strip_number;
    int is_x_meet, is_y_meet;
    int det_idx;
    int layer_num;

    void write_root_file();
    void write_target_root_file();
    void complete_adding();

    // Data out init
    int valid_num = 0;
    int trig_event = 0;
    double kx, ky, bx, by;
    double x_strip[cMAX_DET_LAYER] = {0};
    double y_strip[cMAX_DET_LAYER] = {0};
    double z[cMAX_DET_LAYER] = {0};
    int x_strip_num[cMAX_DET_LAYER] = {0};
    int y_strip_num[cMAX_DET_LAYER] = {0};
    void write_event_json_file(int);
    void write_status_json_file();
    json event_json;
    json status_json;
};
#endif
